/*
 * Log.java	2008/07/28
 *
 * Copyright 2008 Web & Zen Multimedia, All rights reserved.
 * Use is subject to license terms.
 */
package it.wzm.lightweightlog;


import java.util.Properties;


/**
 * 
 * @author Leonardo Celati
 * @version 1.0
 */
public class Log implements Constant{

    /**
     * Service log
     */
    private static boolean serviceLogEnabled;
    
    /**
     * Status
     */
    public enum Status {
    	INIT,
    	RUNNING,
    	FAILURE,
    	SHUTDOWN,
    	DEFAULT,
    }
    /**
     * Set the name for this log...
     */
    private String name;
    /**
     * Current status of log
     */
    private Status status;
    
    /**
     * Build a default log
     */
    Log() {
    	// building a default set of properties...
    	Properties p = new Properties();
    	// init log...
    	this.setStatus(Status.DEFAULT);
    	this.init(p);
    }
    
	/**
     * Default constructor
     * @param p custom set of properties
     */
    protected Log(Properties p) {
    	// now..we init our log...
    	this.init(p);
    	// this will be useful later on...
    	// because it is searched by the QueueDumper Thread
    	Thread.currentThread().setName("Log");
    }
    
    /**
	 * @return the name
	 */
	public String getName() {
		return name;
	}

	/**
	 * @param name the name to set
	 */
	void setName(String name) {
		this.name = name;
	}

	/**
     * Setter for status
     * @param status status for Log
     */
    private void setStatus(Status status) {
		this.status = status;
	}

    /**
     * Getter for status
     * @return Status for logger
     */
	public Status getStatus() {
		return status;
	}

	/**
     * Is service log enabled ?
     * @return true or false
     */
    public static boolean isServiceLogEnabled() {
		return serviceLogEnabled;
	}

    /**
     * Preinit...
     */
    void preinit(){
    }
    
    /**
     * Private method for init our Log
     */
    protected void init(Properties p) {

    	// basic assert...
    	assert(p != null && !p.isEmpty()): "Property null or empty";

    	// perform pre init if required...
    	this.preinit();
       
        // get desired Entry...or default if not found...
        String entryClass = p.getProperty(PROP_ROOT + "entry", Constant.DEFAULT_ENTRY);
        
        // post init if required...
        this.postinit();
    }
    
    /**
     * Postinit...
     */
    void postinit() {    	
    }
    
    /**
     * Get all debug level
     * @param tolog The object to be logged
     */
    public void debug(Object tolog) {
        this.add(tolog, new Throwable(), Severity.DEBUG);
    }

    /**
     * Get all info level
     * @param tolog The object to be logged
     */
    public void info(Object tolog) {
        this.add(tolog, new Throwable(), Severity.INFO);
    }

    /**
     * Get all warn level
     * @param tolog The object to be logged
     */
    public void warn(Object tolog) {
        this.add(tolog, new Throwable(), Severity.WARN);
    }

    /**
     * Get all error level
     * @param tolog The object to be logged
     */
    public void error(Object tolog) {
        this.add(tolog, new Throwable(), Severity.ERROR);
    }

    /**
     * Get all fatal level
     * @param tolog The object to be logged
     */
    public void fatal(Object tolog) {
        this.add(tolog, new Throwable(), Severity.FATAL);
    }

    /**
     * Build an Entry from the passed Object and Store it in Queue
     * @param tolog Object to log
     * @param severity The level of Severity
     * @param t A throwable for getting the caller of this error
     */
    protected void add(Object tolog, Throwable t, Severity severity) {
        // log holder
        Entry e = null;
        // decide if we want to log a string or an exception
        if (tolog != null && tolog instanceof Exception) {
            e = new Entry(getName(),new Exception((Exception) tolog), severity, System.currentTimeMillis());
        } else {
            e = new Entry(getName(),tolog, severity, t.getStackTrace()[t.getStackTrace().length - 1].getClassName(), System.currentTimeMillis());
        }
        // in service log...
        serviceLog(e.getLine());
    }
    


    /**
     * Facility for logging everything passed, which will be written to System.err. Useful for debugging.
     * @param o The object to write to log
     */
    public void serviceLog(Object o) {
    	
        // basic check...
        if (!serviceLogEnabled) {
            return;
        }
        // building our entry
        Entry e;
        // check if we want to log instance of Exception or not...
        if (o != null && o instanceof Exception) {
            e = new Entry(getName(),new Exception((Exception) o), Severity.SERVICE, System.currentTimeMillis());
        } else {
            Throwable t = new Throwable();
            e = new Entry(getName(),o, Severity.SERVICE, t.getStackTrace()[t.getStackTrace().length - 1].getClassName(), System.currentTimeMillis());
        }
        // finally logging
        System.err.print(e.getLine());
    }

    /**
     * Facility for logging a passed  Entry which will be written to System.err. Useful for debugging.
     * @param o The object to write to log
     */
    public static <E extends Entry> void serviceLog(E e) {
        System.err.print(e.getLine());
    }
    
    /**
     * Dump E to service log
     * @param <E> 
     * @param e Anything extending Entry
     */
	public  <E extends Entry> void add(E e) {
        // finally add to queue...
        try {
        	// we will try to store entry in Queue...
        	// if we fail we try to recover the Queue.
			LogFactory.getQueue().push(e);
		} catch (QueueException ex) {
			//ex.printStackTrace();
			
		}
    }
    
    
    /**
     * Extending class can implements their own cleanup stuff here
     */
    public void shutdown() {    	
    }
    
 
}